package com.beiing.leafchat;

import com.beiing.leafchat.support.LeafUtil;
import ohos.agp.components.VelocityDetector;
import ohos.multimodalinput.event.TouchEvent;

public class GestureDetector {
    public interface OnGestureListener {

        /**
         * 发生滚动时回调
         *
         * @param e1 手指按下时的事件
         * @param e2 手指移动时的事件
         * @param distanceX 横向的移动距离
         * @param distanceY 纵向的移动距离
         * @return null 无
         */
        boolean onScroll(TouchEvent e1, TouchEvent e2, float distanceX, float distanceY);

    }

    private int mTouchSlopSquare;
    private final OnGestureListener mListener;

    private boolean mAlwaysInTapRegion;

    private TouchEvent mCurrentDownEvent;

    private float mLastFocusX;
    private float mLastFocusY;
    private float mDownFocusX;
    private float mDownFocusY;

    private VelocityDetector mVelocityTracker;

    public GestureDetector(OnGestureListener listener) {
        mListener = listener;
        int touchSlop = 8;
        // 滑动的时候，手指的移动要大于这个距离才算发生了滚动
        mTouchSlopSquare = touchSlop * touchSlop;
    }

    public boolean onTouchEvent(TouchEvent ev) {
        final int action = ev.getAction();

        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityDetector.obtainInstance();
        }
        mVelocityTracker.addEvent(ev);

        final boolean pointerUp =
                action == TouchEvent.OTHER_POINT_UP;
        final int skipIndex = pointerUp ? ev.getIndex() : -1;

        float sumX = 0, sumY = 0;
        final int count = ev.getPointerCount();
        // 把所有还在触摸的手指的位置x，y加起来，后面求平均数，算出中心焦点
        for (int i = 0; i < count; i++) {
            if (skipIndex == i) {
                // 跳过非主要指针的抬起动作
                continue;
            }
            sumX = LeafUtil.add(sumX, ev.getPointerPosition(i).getX());
            sumY = LeafUtil.add(sumY, ev.getPointerPosition(i).getY());
        }
        final int div = pointerUp ? count - 1 : count;
        // 求平均值，算出中心焦点
        final float focusX = sumX / div;
        final float focusY = sumY / div;

        boolean handled = false;

        switch (action) {
            case TouchEvent.OTHER_POINT_DOWN:
                mDownFocusX = mLastFocusX = focusX;
                mDownFocusY = mLastFocusY = focusY;
                break;

            case TouchEvent.OTHER_POINT_UP:
                mDownFocusX = mLastFocusX = focusX;
                mDownFocusY = mLastFocusY = focusY;
                break;

            case TouchEvent.PRIMARY_POINT_DOWN:
                mDownFocusX = mLastFocusX = focusX;
                mDownFocusY = mLastFocusY = focusY;
                mCurrentDownEvent = ev;
                mAlwaysInTapRegion = true;
                break;

            case TouchEvent.POINT_MOVE:
                final float scrollX = LeafUtil.add(mLastFocusX, -focusX);
                final float scrollY = LeafUtil.add(mLastFocusY, -focusY);
                if (mAlwaysInTapRegion) {
                    final int deltaX = (int) LeafUtil.add(focusX, -mDownFocusX);
                    final int deltaY = (int) LeafUtil.add(focusY, -mDownFocusY);
                    int distance = (deltaX * deltaX) + (deltaY * deltaY);
                    int slopSquare = mTouchSlopSquare;

                    if (distance > slopSquare) {
                        handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
                        mLastFocusX = focusX;
                        mLastFocusY = focusY;
                        mAlwaysInTapRegion = false;
                    }
                } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
                    handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
                    mLastFocusX = focusX;
                    mLastFocusY = focusY;
                }
                break;

            case TouchEvent.PRIMARY_POINT_UP:
                break;

            case TouchEvent.CANCEL:
                break;
        }
        return handled;
    }
}
